#include "classes.h"
#include "mytools.h"
#include <iostream>
#include <string>

/// @brief 注入类名实例的实现
/// @tparam T
template <class T> void Y<T>::g() {
  Y *p;      // OK，Y 是注入类名
  Y<int> *q; // OK，Y 是注入类名，但 Y<int> 不是
}

/// @brief 泛型类方法的实现
template <typename T> void Person<T>::walk() {
  std::cout << "Person: " << this->name << " is walking" << std::endl;
}

/// @brief 友元函数
/// @tparam T
/// @param p
template <typename T> void print_private(const Person<T> &p) {
  std::cout << "Private data: " << p.secret_age << std::endl;
}

/// @brief  类声明
void class_declaration() {
  print_title("Class declaration");
  class MyClass {
  public:
    MyClass() = default;                // 默认构造函数
    MyClass(int data) : myData(data) {} // 带参数的构造函数
    void myMethod() {
      std::cout << "Hello from MyClass::myMethod()" << std::endl;
      // 打印 myData
      std::cout << "myData = " << myData << std::endl;
      std::cout << "myData = " << this->myData << std::endl; // 等价于上一行
    }

  private:
    int myData;
  };

  MyClass myObject1;
  MyClass myObject2(10);
  myObject2.myMethod();
}

/// @brief 类构造函数
void class_constructor() { print_title("Class constructor"); }

/// @brief 注入类名
/// @details
/// 注入类名是指在类声明中使用模板参数，从而使得类名在编译时刻就确定下来。
/// 注入类名的好处是可以避免名称查找时的歧义，使得代码更加易读。
void injected_class_name() {
  print_title("Injected class name");
  {
    int X;

    struct X {
      void f() {
        X *p; // OK，X 是注入类名
        // ::X *q; // 错误：名称查找找到变量名，它隐藏结构体名
      }
    };

    // 注意查看 Y 的声明
    Y<int> y;
    y.g();
  }
}

/// @brief 类写法示例
void class_example() {
  print_title("Class example");
  Person p1("Alice", 25);          // 调用默认构造函数
  auto p2 = new Person("Bob", 30); // 指针调用构造函数
  p1.walk();
  p2->walk();

  p1.setName("Charlie");
  p1.walk();
  delete p2;
}

/// @brief 友元函数示例
void friend_function() {
  print_title("Friend function");
  auto *p1 = new Person("Alice", 25, 100);
  // auto p1 = Person<int>("Alice", 25, 100);
  Person p2("Bob", 30, 200);
  print_private(*p1);
  print_private(p2);
  // free(p1);
  delete p1;
}
